package com.qiongqi.datadir.controller;

import com.qiongqi.datadir.common.AjaxResult;
import com.qiongqi.datadir.common.BaseController;
import com.qiongqi.datadir.domain.Certificate;
import com.qiongqi.datadir.envm.CertStatus;
import com.qiongqi.datadir.helper.VaultHelper;
import com.qiongqi.datadir.service.ICertificateService;
import com.qiongqi.datadir.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.KeyPair;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.qiongqi.datadir.consts.Constants.EC_CURVE_NAME;
import static com.qiongqi.datadir.envm.CertStatus.EXPIRED;
import static com.qiongqi.datadir.envm.CertStatus.VALID;
import static com.qiongqi.datadir.utils.DnToStableVaultPath.convertToVaultPath;
import static com.qiongqi.datadir.utils.json.JsonSerializer.OBJECT_MAPPER;
import static com.qiongqi.datadir.utils.security.PREUtils.generateCSR;
import static com.qiongqi.datadir.utils.security.PREUtils.generateECKeyPair;
import static java.util.Objects.nonNull;
import static org.apache.commons.collections4.MapUtils.getString;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

@Slf4j
@Controller
@RequestMapping("/cert")
public class CertificateController extends BaseController {

    @Autowired
    private ICertificateService certificateService;

    @Autowired
    private VaultHelper vaultHelper;

    /**
     * 凭证主页
     */
    @GetMapping
    public String index()
    {
        return "certificate";
    }

    /**
     * 检查凭证状态
     */
    @PostMapping("/pairKey")
    @ResponseBody
    public AjaxResult pairKey(@RequestBody Map<String, Object> requestMap)
    {
        Map<String, String> pairMap = new HashMap<>();
        try {
            String subject = getString(requestMap, "subject");
            if(isNotBlank(subject)) {
                Certificate cert = certificateService.selectOnlyCertificate();
                Date currentTime = DateUtils.getNowDate();
                CertStatus status = currentTime.before(cert.getNotAfter()) ? VALID : EXPIRED;
                if (status == VALID) {
                    log.warn("证书还未过期");
                }
                KeyPair kp = generateECKeyPair(EC_CURVE_NAME);
                String csr = generateCSR(kp, subject);
                pairMap.put("keyAlgorithm", "EC");
                pairMap.put("publicKey", kp.getPublic().toString());
                pairMap.put("privateKey", kp.getPrivate().toString());
                pairMap.put("subject", subject);
                pairMap.put("csr", csr);
                return success(pairMap);
            }else{
                log.error("Invalid inputted DN:{}", subject);
                return error("非法的DN名称，请检查");
            }
        } catch (IOException ex1) {
            log.error("Failed to get certificate status:{}", ex1);
            return error("无法获取凭证状态，请检查");
        } catch (Exception ex2) {
            log.error("Failed to generate key pair:{}", ex2);
            return error("无法产生密钥对，请检查");
        }
    }

    /**
     * 保存私钥
     */
    @PostMapping("/savePrivKey")
    @ResponseBody
    public AjaxResult savePrivKey(@RequestBody Certificate certificate)
    {
        try {
            String subject = nonNull(certificate) ? certificate.getSubject() : "";
            if(isNotBlank(subject)) {
                Map<String, Object> certMap = OBJECT_MAPPER.convertValue(certificate, Map.class);
                //boolean vaultResp = vaultHelper.writeKV(convertToVaultPath(subject), "register", certMap);
                boolean vaultResp = false;
                if(vaultResp){
                    int ret = certificateService.saveOrUpdateCert(certificate);
                    vaultResp = ret > 0;
                }
                return vaultResp ? success() : error();
            }else{
                log.error("Invalid inputted param:{}", certificate);
                return error("非法的DN名称，请检查");
            }
        } catch (Exception ex) {
            log.error("Failed to save key in vault:{}", ex);
            return error("无法保存密钥，请检查");
        }
    }

    /**
     * 检查凭证状态
     */
    @GetMapping("/status")
    @ResponseBody
    public AjaxResult status()
    {
        HashMap<String, Object> retMap = new HashMap<>();
        try {
            Certificate cert = certificateService.selectOnlyCertificate();
            Date currentTime = DateUtils.getNowDate();
            CertStatus status = currentTime.before(cert.getNotAfter()) ? VALID : EXPIRED;
            retMap.put("certificate", cert);
            retMap.put("status", status.name());
        } catch (IOException e) {
            log.error("Failed to get certificate status:{}", e);
            retMap.put("status", EXPIRED.name());
        }
        return success(retMap);
    }

    /**
     * 上传凭证
     */
    @PostMapping("/upload")
    @ResponseBody
    public AjaxResult handleFileUpload(@RequestParam("file") MultipartFile file) {
        AjaxResult ret = null;
        try {
            String storagePath = certificateService.uploadFile(file);
            Map<String, String> dataMap = new HashMap<>();
            dataMap.put("path", storagePath);
            dataMap.put("fname", file.getOriginalFilename());
            ret = success(dataMap);
        } catch (IOException e) {
            log.error("上传失败:{}", e);
            ret = error("上传失败:" + e.getMessage());
        }
        return ret;
    }

}
